// 8、从一个简单的例子引入
// 模特类
class Model {
  sex: string;
  custom: number;
  constructor(sex: string, custom: number) {
    this.sex = sex;
    this.custom = custom;
  }
  takePicture() {
    console.log(`性别：${this.sex},服装：${this.custom}`);
  }
}
// 各找50个模特来拍照
for (let i = 0; i < 50; i++) {
  let maleModel = new Model("男", i);
  maleModel.takePicture();
}
for (let i = 0; i < 50; i++) {
  let femaleModel = new Model("女", i);
  femaleModel.takePicture();
}

// 改良的模特类
class NewModel {
  sex: string;
  constructor(sex: string) {
    this.sex = sex;
  }
  takePicture(custom: number) {
    console.log(`性别：${this.sex},服装：${custom}`);
  }
}
// 各找50个模特来拍照
for (let i = 0; i < 50; i++) {
  let maleModel = new NewModel("男");
  maleModel.takePicture(i);
}
for (let i = 0; i < 50; i++) {
  let femaleModel = new NewModel("女");
  femaleModel.takePicture(i);
}

// 文件上传的例子--->1
class Upload {
  uploadType: string;
  filename: string;
  fileSize: number;
  id: number | null;
  constructor(uploadType: string, filename: string, fileSize: number) {
    this.uploadType = uploadType;
    this.filename = filename;
    this.fileSize = fileSize;
    this.id = null;
  }
  init(id: number) {
    this.id = id;
    console.log("上传已经初始化完成了。");
  }
}
// 下载初始化函数
let fileId = 0;
function startUpload(uploadType: string, files: any) {
  for (let i = 0; i < files.length; i++) {
    const uploadObj = new Upload(
      uploadType,
      files[i].filename,
      files[i].fileSize
    );
    uploadObj.init(fileId); // 已经初始化完成
    fileId++; // 文件id唯一
  }
}

startUpload("plugin", [
  {
    fileName: "1.txt",
    fileSize: 1000,
  },
  {
    fileName: "2.html",
    fileSize: 3000,
  },
  {
    fileName: "3.txt",
    fileSize: 5000,
  },
]);
startUpload("flash", [
  {
    fileName: "4.txt",
    fileSize: 1000,
  },
  {
    fileName: "5.html",
    fileSize: 3000,
  },
  {
    fileName: "6.txt",
    fileSize: 5000,
  },
]);

// 文件上传的例子--->2
// 改良后的upload类
class NewUpload {
  uploadType: string;
  constructor(uploadType: string) {
    this.uploadType = uploadType;
  }
}
// 创建upload享元对象的工厂方法
const uploadFactory = (function() {
  let flyWeightedMap: any = {}; // 享元对象的哈希表
  return function(uploadType: string) {
    if (flyWeightedMap[uploadType]) {
      return flyWeightedMap[uploadType];
    }
    flyWeightedMap[uploadType] = new NewUpload(uploadType);
    return flyWeightedMap[uploadType];
  };
})();
// upload对象的外部状态管理方法
const uploadStateManager = (function() {
  let uploadDataBase: any = {};
  return {
    add(id: number, uploadType: string, fileName: string, fileSize: number) {
      // 创建享元对象及初始化方法
      let flyWeightedObj = uploadFactory(uploadType); // 创建一个享元对象
      console.log("上传已经初始化完成了。");
      uploadDataBase[id] = {
        // uploadDataBase对象负责记录外部状态
        fileName,
        fileSize,
      };
      return flyWeightedObj; // 返回享元对象
    },
    /**
     * @param id 唯一标识的id号
     * @param flyWeightedObj 享元对象本身
     */
    // 会根据情况实时的动态改写享元对象
    setExternalState(id: number, flyWeightedObj: any) {
      // 设置外部状态方法
      let state = uploadDataBase[id];
      for (let key in state) {
        flyWeightedObj[key] = state[key];
      }
    },
  };
})();
// 重写startUpload方法
let _id = 0;
function startUpload2(uploadType: string, files: any) {
  for (let i = 0; i < files.length; i++) {
    uploadStateManager.add(_id, uploadType, files.fileName, files.fileSize);
  }
}
// 测试用例
startUpload2("plugin", [
  {
    fileName: "1.txt",
    fileSize: 1000,
  },
  {
    fileName: "2.html",
    fileSize: 3000,
  },
  {
    fileName: "3.txt",
    fileSize: 5000,
  },
]); // 上传初始化已经完成

// 没有内部状态的上传类
class NewUpload2 {}
// 没有内部状态的工厂函数--->单例
const uploadFactory2 = (function() {
  var flyWeightedObj: any = null;
  return {
    created() {
      if (flyWeightedObj) {
        return flyWeightedObj;
      }
      flyWeightedObj = new NewUpload2();
      return flyWeightedObj;
    },
  };
})();

// div对象池
const bubbleFactory = (function() {
  const bubbleList: HTMLDivElement[] = []; // 对象池
  return {
    create(): HTMLDivElement {
      // 从对象池中取一个div标签
      return (bubbleList.length === 0
        ? document.createElement("div")
        : bubbleList.shift()) as HTMLDivElement;
    },
    recover(divDom: HTMLDivElement) {
      // 回收一个div标签
      bubbleList.push(divDom);
    },
  };
})();

// 测试用例

// 第一次绘制
const tempList: HTMLDivElement[] = []; // 临时存放的数组
function firstPaint() {
  // 需要用stringData1来进行dom的生成
  const stringData1: string[] = ["data1", "data2", "data3", "data4"];
  for (let i = 0; i < stringData1.length; i++) {
    const div = bubbleFactory.create();
    div.innerHTML = stringData1[i];
    document.body.appendChild(div);
    tempList.push(div);
  }
}

// 重新绘制前回收
function recoverDiv() {
  document.body.innerHTML = "";
  while (tempList.length > 0) {
    bubbleFactory.recover(tempList.shift() as HTMLDivElement);
  }
}

// 第二次绘制
function secordPaint() {
  // 需要用stringData2来进行dom的生成
  const stringData2: string[] = ["data5", "data6", "data7", "data8", "data9"];
  for (let i = 0; i < stringData2.length; i++) {
    const div = bubbleFactory.create();
    div.innerHTML = stringData2[i];
    document.body.appendChild(div);
    tempList.push(div);
  }
}

// 绘制过程
firstPaint();
setTimeout(recoverDiv, 4000);
setTimeout(secordPaint, 8000);

// 通用对象池的封装
function createObjectPool<T>(createCallback: () => T) {
  const objectPool: T[] = [];
  return {
    create() {
      return (objectPool.length === 0
        ? createCallback.call(this)
        : objectPool.shift())!;
    },
    recover(obj: T) {
      objectPool.push(obj);
    },
  };
}

// 测试用例
// 水壶接口
interface IBottle {
  size: string;
  contentDrink: string;
}
// 创建一个水壶工厂
function createBottle() {
  return {
    size: "",
    contentDrink: "",
  };
}
const bottlePool = createObjectPool<IBottle>(createBottle);
let bottle1 = bottlePool.create();
bottle1.size = "large";
bottle1.contentDrink = "orange";
bottlePool.recover(bottle1);
let bottle2 = bottlePool.create();
bottle2.size = "medium";
bottle2.contentDrink = "apple";
console.log(bottle1, bottle2, bottle1 === bottle2);
